package mysqlgo

import (
	"fmt"
	"strings"
)

type option struct {
	tables		[]Table
	distinct	bool
	field		string
	join		[]Join
	where		string
	whereArgs	[]interface{}
	group		[]string
	having		string
	order		[]Order
	limit		Limit
	union		Union
	comment		string
	page		string
	args		[]interface{}
}

func (o *option) setTable(table ...Table) {
	o.tables = append(o.tables, table...)
}

func (o *option) setField(fields ...string){
	if len(fields) == 0 {
		o.field = ""
	} else {
		o.field = strings.Join(fields, ",")
	}
}

func (o *option) setDistinct(distinct bool) {
	o.distinct = distinct
}

func (o *option) setJoin(join Join) {
	o.join = append(o.join, join)
}

func (o *option) setWhere(where string, args ...interface{}) {
	if where == "" {
		panic("[option setWhere]: The Where is NULL of string")
	}
	var count = strings.Count(where, "?")
	if count != len(args) {
		panic("[option setWhere]: The '?' of characters and the count of args aren't same")
	}
	o.where = where
	o.whereArgs = args
	o.setArgs(args)
}

func (o *option) setGroup(group ...string) {
	o.group = append(o.group, group...)
}

func (o *option) setHaving(having string) {
	o.having = having
}

func (o *option) setOrder(orders ...Order) {
	o.order = append(o.order, orders...)
}

func (o *option) setUnion(selectSQL []string, all bool) {
	if all {
		o.union.All = true
	}
	o.union.SelectSQL = append(o.union.SelectSQL, selectSQL...)
}

func (o *option) setLimit(limit Limit) {
	o.limit = limit
}

func (o *option) setComment(comment string) {
	o.comment = comment
}

func (o *option) setPage(page uint, listRows uint) {
	o.page = fmt.Sprintf(" %d,%d ", page, listRows)
}

func (o *option) setArgs(args ...interface{}) {
	if len(args) > 0 {
		o.args = append(o.args, args)
	}
}

func (o *option) parseTable() string {
	if len(o.tables) == 0 {
		panic("[option parseTable]: The Tables is NULL")
	}
	var table []string
	for _, Table := range o.tables {
		table = append(table, fmt.Sprintf(" %s %s ", Table.Name, Table.Alias))
	}
	return strings.Join(table, ",") 
}

func (o *option) parseDistinct() string{
	if o.distinct {
		return " DISTINCT "
	} 
	return ""
}

func (o *option) parseField() string {
	if o.field == "" {
		return "*"
	} 
	return o.field
}

func (o *option) parseJoin() string {
	var join []string
	for _, value := range o.join {
		if !(strings.Index(value.Statement, "JOIN") > -1 && strings.Index(value.Statement, "join") > -1) {
			value.Statement = fmt.Sprintf(" JOIN %s ", value.Statement)
		}
		switch value.Type {
		case 0:
			join = append(join, fmt.Sprintf(" INNER %s ", value.Statement))
			break
		case 1:
			join = append(join, fmt.Sprintf(" LEFT %s ", value.Statement))
			break
		case 2:
			join = append(join, fmt.Sprintf(" RIGHT %s ", value.Statement))
			break
		case 3:
			join = append(join, fmt.Sprintf(" FULL %s ", value.Statement))
			break
		default:
			join = append(join, fmt.Sprintf(" INNER %s ", value.Statement))
			break
		}

	}
	return strings.Join(join, ",")
}

func (o *option) parseWhere() string {
	if o.where != "" {
		return fmt.Sprintf(" WHERE %s " , o.where)
	}
	return ""
}

func (o *option) parseGroup() string {
	if len(o.group) > 0 {
		return fmt.Sprintf(" GROUP BY %s", strings.Join(o.group, ",")) 
	}
	return ""
}

func (o *option) parseHaving() string {
	if o.having != "" {
		return fmt.Sprintf(" HAVING %s", o.having) 
	}
	return ""
}

func (o *option) parseComment() string {
	if o.comment != "" {
		return fmt.Sprintf(" /* %s */", o.comment)
	}
	return ""
}

func (o *option) parseOrder() string {
	if len(o.order) > 0 {
		var orderStr []string
		for _, order := range o.order {
			var str string
			if order.Desc {
				str = fmt.Sprintf(" %s desc", order.Field)
			} else {
				str = fmt.Sprintf(" %s asc", order.Field)
			}
			orderStr = append(orderStr, str)
		}
		return fmt.Sprintf(" ORDER BY %s ", strings.Join(orderStr, ","))
	}
	return ""
}

func (o *option) parseLimit() string {
	if o.limit.Offset > 0 {
		if o.limit.Length > 0 {
			return fmt.Sprintf(" LIMIT %d, %d " , o.limit.Offset, o.limit.Length)
		}
		return fmt.Sprintf(" Limit %d " , o.limit.Offset)
	}
	return ""
}

func (o *option) parseUnion() string {
	if len(o.union.SelectSQL) > 0 {
		if o.union.All {
			return fmt.Sprintf(" UNION ALL %s ", strings.Join(o.union.SelectSQL, ","))
		}
		return fmt.Sprintf(" UNION %s ", strings.Join(o.union.SelectSQL, ","))
	}
	return ""
}

func (o *option) parseFiledMark() string {
	if o.field == "*" {
		panic("[option parseFiledMark]: The Field is NULL of string")
	}
	var count = strings.Count(o.field, ",")
	var fieldMark []string
	for i := 0 ; i <= count ; i ++ {
		fieldMark = append(fieldMark, "?")
	}
	if len(fieldMark) == 0 {
		panic("[option parseFiledMark]: The Field is NULL of string")
	}
	return strings.Join(fieldMark, ",")
}

//Table 数据表
type Table struct {
	Name 	string	//表名
	Alias	string	//别名
}

//Order 结果排序
type Order struct {
	Field 	string 	//排序字段
	Desc	bool	//排序方式: 默认false为asc排序，true为desc排序
}

//Limit 查询和操作的记录数量
type Limit struct {
	Offset	int		//起始位置，默认为0
	Length	int		//查询数量，默认为10	
}

//Join 表之间关系 
///Join语句，不用加join前缀
///Join类型，默认0
///0为INNER JOIN: 如果表中有至少一个匹配，则返回行，等同于 JOIN
///1为LEFT JOIN: 即使右表中没有匹配，也从左表返回所有的行
///2为RIGHT JOIN: 即使左表中没有匹配，也从右表返回所有的行
///3为FULL JOIN: 只要其中一个表中存在匹配，就返回行
type Join struct {
	Statement 	string	
	Type		int		
}

//Union 合并Select
type Union struct {
	SelectSQL 	[]string
	All			bool 
}

//Data 数据元素
type Data struct {
	Field	string
	Value	interface{}
}